using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using IronPython;
using IronPython.Hosting;
using log4net;
using Microsoft.Scripting.Hosting;
using Triton.Common.LogUtilities;

namespace Triton.Common
{
	public class ScriptManager
	{
		public class InputOutputProxy
		{
			private readonly ILog ilog_0;

			public InputOutputProxy()
			{
				ilog_0 = Logger.GetLoggerInstanceForType();
			}

			public InputOutputProxy(ILog log)
			{
				ilog_0 = log;
			}

			public void write(string s)
			{
				ilog_0.DebugFormat("{0}", s);
			}
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class Class233
		{
			public static readonly Class233 Instance9 = new Class233();

			public static Func<ParameterInfo, Type> Instance9__11_0;

			public static Func<string, bool> Instance9__17_0;

			internal Type method_0(ParameterInfo parameterInfo_0)
			{
				return parameterInfo_0.ParameterType;
			}

			internal bool method_1(string string_0)
			{
				return !string.IsNullOrEmpty(string_0);
			}
		}

		private ILog ilog_0;

		private ScriptEngine scriptEngine_0;

		private ScriptScope scriptScope_0;

		private readonly AppDomain appDomain_0;

		private static readonly List<string> list_0 = new List<string>
		{
			"System", "System.Threading", "System.Diagnostics", "System.Linq", "System.Linq.Expressions", "System.Windows.Media", "System.Text", "System.Collections", "System.Collections.Concurrent", "System.Collections.Generic",
			"System.Collections.ObjectModel"
		};

		private const string string_0 = "import clr\r\nclr.ImportExtensions(System.Linq)\r\n";

		[CompilerGenerated]
		private InputOutputProxy inputOutputProxy_0;

		public ScriptEngine Engine => scriptEngine_0;

		public ScriptScope Scope => scriptScope_0;

		public InputOutputProxy IoProxy
		{
			[CompilerGenerated]
			get
			{
				return inputOutputProxy_0;
			}
			[CompilerGenerated]
			set
			{
				inputOutputProxy_0 = value;
			}
		}

		public ScriptManager(AppDomain domain)
		{
			appDomain_0 = domain;
		}

		public ScriptManager()
		{
			appDomain_0 = AppDomain.CurrentDomain;
		}

		private static Delegate smethod_0(MethodInfo methodInfo_0)
		{
			return Delegate.CreateDelegate(Expression.GetDelegateType((from parameterInfo_0 in methodInfo_0.GetParameters()
				select parameterInfo_0.ParameterType).Concat(new Type[1] { methodInfo_0.ReturnType }).ToArray()), null, methodInfo_0);
		}

		public void Deinitialize()
		{
			appDomain_0.AssemblyLoad -= appDomain_0_AssemblyLoad;
			scriptEngine_0 = null;
			scriptScope_0 = null;
		}

		public void Initialize(IEnumerable<Type> shortcutsDefinitions, IEnumerable<string> customNamespaces)
		{
			Initialize(Logger.GetLoggerInstanceForType(), shortcutsDefinitions, customNamespaces);
		}

		public void Initialize(ILog log, IEnumerable<Type> shortcutsDefinitions, IEnumerable<string> customNamespaces)
		{
			ilog_0 = log;
			if (IoProxy == null)
			{
				IoProxy = new InputOutputProxy(ilog_0);
			}
			try
			{
				Dictionary<string, object> options = new Dictionary<string, object> { 
				{
					"DivisionOptions",
					PythonDivisionOptions.New
				} };
				scriptEngine_0 = Python.CreateEngine(options);
				Assembly[] assemblies = appDomain_0.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					scriptEngine_0.Runtime.LoadAssembly(assembly);
				}
				scriptScope_0 = scriptEngine_0.CreateScope();
				method_0(customNamespaces);
				if (shortcutsDefinitions != null)
				{
					foreach (Type shortcutsDefinition in shortcutsDefinitions)
					{
						MethodInfo[] methods = shortcutsDefinition.GetMethods(BindingFlags.Static | BindingFlags.Public);
						foreach (MethodInfo methodInfo in methods)
						{
							if (!methodInfo.Name.ToLowerInvariant().Contains("init"))
							{
								Delegate value = smethod_0(methodInfo);
								scriptScope_0.SetVariable(methodInfo.Name, value);
							}
						}
					}
				}
				appDomain_0.AssemblyLoad += appDomain_0_AssemblyLoad;
			}
			catch (Exception exception)
			{
				ilog_0.Error("Exception while loading Python runtime. Exception follows", exception);
			}
		}

		private void appDomain_0_AssemblyLoad(object sender, AssemblyLoadEventArgs e)
		{
			scriptEngine_0.Runtime.LoadAssembly(e.LoadedAssembly);
		}

		private void method_0(IEnumerable<string> ienumerable_0)
		{
			List<string> list = new List<string>(list_0);
			list.AddRange(ienumerable_0.Where((string string_0) => !string.IsNullOrEmpty(string_0)));
			StringBuilder stringBuilder = new StringBuilder();
			foreach (string item in list)
			{
				stringBuilder.AppendLine("import " + item);
			}
			foreach (string item2 in list)
			{
				stringBuilder.AppendLine("from " + item2 + " import *");
			}
			stringBuilder.AppendLine("import clr\r\nclr.ImportExtensions(System.Linq)\r\n");
			scriptEngine_0.Execute(stringBuilder.ToString(), scriptScope_0);
		}

		public Action GetStatement(string statement)
		{
			ScriptSource scriptSource = scriptEngine_0.CreateScriptSourceFromString(statement.Trim());
			scriptScope_0.SetVariable("ioproxy", IoProxy);
			scriptSource.Execute(scriptScope_0);
			return scriptScope_0.GetVariable<Action>("Execute");
		}

		public string FormatSyntaxErrorException(Exception ex)
		{
			return scriptEngine_0.GetService<ExceptionOperations>(Array.Empty<object>()).FormatException(ex);
		}
	}
}
